#include <memory>

#include "TcpServer.hpp"
#include "Protocol.hpp"
#include "Calculator.hpp"
#include "Deamon.hpp"

using cal_t = std::function<Response(Request &req)>;

// package不一定是完整的！
// 1. 不完整: 继续读取
// 2. 完整: 直接提取, 执行以下步骤
class Parse
{
public:
    Parse() {}

    Parse(cal_t cal)
        : _cal(cal)
    {}

    std::string Entry(std::string &package)
    {
        std::string message;
        std::string respstr;

        // 1. 删除报头字段(连续处理多个报文)
        LOG(LogLevel::DEBUG) << "接收的报文: \n" << package;
        while (Decode(package, &message))
        {
            LOG(LogLevel::DEBUG) << "删除报头字段: \n" << message;
            if (message.empty())
                break;

            // 2. 反序列化
            Request req;
            req.Deserialize(message);
            LOG(LogLevel::DEBUG) << "反序列化: ";
            req.Print();

            // 3. 响应请求
            Response resp = _cal(req);
            LOG(LogLevel::DEBUG) << "计算: ";
            resp.Print();

            // 4. 序列化
            std::string res;
            resp.Serialize(res);
            LOG(LogLevel::DEBUG) << "序列化: \n" << res;

            // 5. 添加报头字段
            Encode(res);
            LOG(LogLevel::DEBUG) << "添加报头字段: \n" << res;

            // 6. 拼接应答
            respstr += res;
        }
        LOG(LogLevel::DEBUG) << "发送的报文: \n" << respstr;

        return respstr;
    }

private:
    cal_t _cal;
};

int main()
{
    ENABLE_FILE_LOG(); // 往文件中打印

    Deamon(false, false); // 守护进程

    // 1. 计算模块: 应用层
    Calculator cal;

    // 2. 解析模块: 表示层(序列化和反序列化)
    Parse parse([&cal](const Request &req){
        return cal.Execute(req);
    });
    // Parse parse(std::bind(&Calculator::Execute, std::ref(cal), std::placeholders::_1));

    // 3. 通信模块: 网络层
    std::shared_ptr<TcpServer> tsvr = std::make_shared<TcpServer>([&parse](std::string &package){
        return parse.Entry(package);
    });
    // std::shared_ptr<TcpServer> tsvr = std::make_shared<TcpServer>(std::bind(&Parse::Entry, std::ref(parse), std::placeholders::_1));

    tsvr->InitServer();
    tsvr->Start();

    return 0;
}